package function

import (
	"crypto/ecdsa"
	"crypto/elliptic"
	"crypto/rand"
	"crypto/sha256"
	"crypto/x509"
	"encoding/hex"
	"encoding/pem"
	"fmt"
	"io/ioutil"
	"log"
	"math/big"
	"os"
	"strings"
)


func Sign(data []byte,nodeSeq int)string{
	//fmt.Printf("生成签名：\n")
	prikey:=getPrivateKey(nodeSeq)
	msg:=sha256.Sum256(data)
	r ,s,_:=ecdsa.Sign(rand.Reader,&prikey,msg[:])
	strSigR :=fmt.Sprint(r)
	strSigS:=fmt.Sprint(s)
	//strSigR :=fmt.Sprintf("%x",r)
	//strSigS :=fmt.Sprintf("%x",s)
	//fmt.Println("r、s的十进制分别为",r,s)
	//fmt.Println("r、s的十六进制分别为：",strSigR,strSigS)
	//signatureDer:=MakeSignatureDerString(strSigR,strSigS)//签名的der格式
	//fmt.Println("数字签名DER格式为：",signatureDer)
	//res :=VerifySig(pubkey,msg[:],r,s)
	//fmt.Println("签名结果：",res)
	//res =VerifySignature(pubkey,msg[:],strSigR,strSigS)
	//fmt.Println("签名结果：",res)
	return strSigR+":"+strSigS
}


func SignHash(msg [32]byte,nodeSeq int)string{
	prikey:=getPrivateKey(nodeSeq)
	r ,s,_:=ecdsa.Sign(rand.Reader,&prikey,msg[:])
	strSigR :=fmt.Sprint(r)
	strSigS:=fmt.Sprint(s)
	return strSigR+":"+strSigS
}

func VerifySign(data []byte,sign string,nodeSeq int)bool{
	pubkey:=getPublicKey(nodeSeq)
	msg:=sha256.Sum256(data)
	//var signature []string
	signature :=strings.Split(sign,":")
	strSigR :=signature[0]
	strSigS :=signature[1]
	r, _ :=new(big.Int).SetString(strSigR, 10)
	s, _ :=new(big.Int).SetString(strSigS, 10)
	//res :=verifySignature(pubkey,msg[:],strSigR,strSigS)
	res:=verifySig(pubkey,msg[:],r,s)
	return res
}

func VerifySignHash(msg [32]byte,sign string,nodeSeq int)bool{
	pubkey:=getPublicKey(nodeSeq)
	var signature []string
	signature =strings.Split(sign,":")
	strSigR :=signature[0]
	strSigS :=signature[1]
	r, _ :=new(big.Int).SetString(strSigR, 10)
	s, _ :=new(big.Int).SetString(strSigS, 10)
	//res :=verifySignature(pubkey,msg[:],strSigR,strSigS)
	res:=verifySig(pubkey,msg[:],r,s)
	return res
}

func getPrivateKey(seq int)(ecdsa.PrivateKey){
	//var decrypted string
	var privateKey []byte
	var err error
	//flag.StringVar(&decrypted,"d","","加密过的数据")
	//flag.Parse()
	privateKey,err=ioutil.ReadFile("C:/Users/00/go/src/blockchain/public/key/private"+fmt.Sprint(seq)+".pem")
	if err!=nil{
		println("6666")
		os.Exit(-1)
	}
	block,_:=pem.Decode(privateKey)
	prikey,_:=x509.ParseECPrivateKey(block.Bytes)
	return  *prikey
}


func getPublicKey(seq int)([]byte){
	//var decrypted string
	var publicKey []byte
	var err error
	//flag.StringVar(&decrypted,"d","","加密过的数据")
	//flag.Parse()
	publicKey,err=ioutil.ReadFile("C:/Users/00/go/src/blockchain/public/key/public"+fmt.Sprint(seq)+".pem")
	if err!=nil{
		println(seq)
		os.Exit(-1)
	}
	block,_:=pem.Decode(publicKey)
	return  block.Bytes
}

func newKeyPair() (ecdsa.PrivateKey, []byte) {
	curve :=elliptic.P256()
	private,err:=ecdsa.GenerateKey(curve,rand.Reader)
	if err !=nil{
		log.Panic(err)
	}
	pubkey:=append(private.X.Bytes(),private.Y.Bytes()...)
	return *private,pubkey
}

func makeSignatureDerString(r,s string)string{
	lenSigR :=len(r)/2
	lenSigS :=len(s)/2
	lenSequence:= lenSigR+lenSigS+4
	strLenSigR :=decimalToHex(int64(lenSigR))
	strLenSigS :=decimalToHex(int64(lenSigS))
	strLenSequence:=decimalToHex(int64(lenSequence))
	derString :="30"+strLenSequence
	derString = derString +"02"+strLenSigR+r
	derString = derString +"02"+strLenSigS+s
	derString = derString +"01"
	return  derString
}

func verifySig(pubkey,message []byte,r,s *big.Int)bool{
	curve :=elliptic.P256()
	keyLen :=len(pubkey)
	x :=big.Int{}
	y :=big.Int{}
	x.SetBytes(pubkey[:(keyLen/2)])
	y.SetBytes(pubkey[(keyLen/2):])
	rawPubKey:=ecdsa.PublicKey{curve,&x,&y}
	res :=ecdsa.Verify(&rawPubKey,message,r,s)
	return res
}

func verifySignature(pubkey,message []byte,r,s string)bool{
	curve :=elliptic.P256()
	keyLen :=len(pubkey)
	x :=big.Int{}
	y :=big.Int{}
	x.SetBytes(pubkey[:(keyLen/2)])
	y.SetBytes(pubkey[(keyLen/2):])
	rawPubKey:=ecdsa.PublicKey{curve,&x,&y}
	rint :=big.Int{}
	sint :=big.Int{}
	rByte,_:=hex.DecodeString(r)
	sByte,_:=hex.DecodeString(s)
	rint.SetBytes(rByte)
	sint.SetBytes(sByte)
	res :=ecdsa.Verify(&rawPubKey,message,&rint,&sint)
	return res
}

func decimalToHex(n int64)string{
	if n<0{
		log.Println("Decimal to hexaDecimal error:小于0")
		return  ""
	}
	if n==0{
		return "0"
	}
	hex :=map[int64]int64{10:65,11:66,12:67,13:68,14:69,15:70}
	s :=""
	for q:=n;q>0;q=q/16{
		m:=q%16
		if m>9&&m<16{
			m=hex[m]
			s=fmt.Sprintf("%v%v",string(m),s)
			continue
		}
		s =fmt.Sprintf("%v%v",m,s)
	}
	return s
}
